package cn.stimd.spring.beans.factory.support;

import cn.stimd.spring.beans.*;
import cn.stimd.spring.beans.factory.Aware;
import cn.stimd.spring.beans.factory.BeanFactoryAware;
import cn.stimd.spring.beans.factory.InitializingBean;
import cn.stimd.spring.beans.factory.ObjectFactory;
import cn.stimd.spring.beans.factory.config.BeanPostProcessor;
import cn.stimd.spring.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.core.ResolvableType;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

/**
 * Created by Stimd
 * 项目地址：https://gitee.com/stimd/spring-wheel
 * 公众号：Java编程探微
 */
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory {
    private InstantiationStrategy instantiationStrategy = new SimpleInstantiationStrategy();


    @Override
    protected Object createBean(String beanName, RootBeanDefinition mbd) {
        RootBeanDefinition mbdToUse = mbd;
        Class<?> resolvedClass = resolveBeanClass(mbd, beanName);

        //hasBeanClass为false，说明Bean的类型没有解析过，需要设置beanClass属性
        if(resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null){
            mbdToUse = new RootBeanDefinition(mbd);
            mbdToUse.setBeanClass(resolvedClass);
        }

        //尝试创建代理对象
        Object bean = applyBeanPostProcessorsBeforeInstantiation(beanName, mbdToUse);
        if (bean != null) {
            return bean;
        }
        return doCreateBean(beanName, mbdToUse);
    }


    protected Object applyBeanPostProcessorsBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
        if (!mbd.isSynthetic()) {
            Class<?> targetType = determineTargetType(beanName, mbd);
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof InstantiationAwareBeanPostProcessor) {
                    InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                    Object result = ibp.postProcessBeforeInstantiation(targetType, beanName);
                    if (result != null) {
                        return result;
                    }
                }
            }
        }
        return null;
    }


    protected Object doCreateBean(String beanName, RootBeanDefinition mbd) {
        //1. Bean的实例化
        BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd);
        Object bean = instanceWrapper.getWrappedInstance();
        Class<?> beanType = instanceWrapper.getWrappedClass();
        mbd.resolvedTargetType = beanType;

        //2. 提前暴露Bean以解决循环依赖
        boolean earlySingletonExposure = isSingletonCurrentlyInCreation(beanName);
        if(earlySingletonExposure){
            //这里的ObjectFactory是将创建中的Bean缓存起来，与AbstractBeanFactory中的ObjectFactory不一样
            //如果依赖的是一个代理，那么此时的bean是目标对象，而我们实际需要指向的是代理对象，否则aop便会失效
            //因此我们需要提前创建代理对象。一般来说，代理都是在[初始化后]创建的，暂不考虑[实例化前]创建代理的情况
            addSingletonFactory(beanName, new ObjectFactory<Object>() {
                @Override
                public Object getObject() throws BeansException {
                    return getEarlyBeanReference(beanName, mbd, bean);
                }
            });
        }

        Object exposedObject = bean;
        try {
            //3. 填充对象
            populateBean(beanName, mbd, instanceWrapper);
            //4. 初始化
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }catch (Throwable t){
            throw new BeansException("初始化Bean[" + beanName + "]失败", t);
        }

        //如果Bean在创建中，取出二级缓存中的引用（可能是一个代理）
        //填充对象和初始化的操作都是针对目标对象，但是最后需要返回的是一个代理
        if(earlySingletonExposure){
            Object earlySingletonReference = getSingleton(beanName, false);
            if (earlySingletonReference != null && exposedObject == bean) {
                exposedObject = earlySingletonReference;
            }
        }

        //5. 注册待销毁的Bean
        registerDisposableBeanIfNecessary(beanName, bean, mbd);
        return exposedObject;
    }


    protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
        Object exposedObject = bean;
        if (bean != null && !mbd.isSynthetic()) {
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof InstantiationAwareBeanPostProcessor) {
                    InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                    exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
                    if (exposedObject == null) {
                        return null;
                    }
                }
            }
        }
        return exposedObject;
    }


    //创建Bean实例
    private BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd) {
        //1. 工厂方法
        if(mbd.getFactoryMethodName() != null){
            return new ConstructorResolver(this).instantiateUsingFactoryMethod(beanName, mbd);
        }

        //2. 构造器注入
        Class<?> beanClass = resolveBeanClass(mbd, beanName);
        Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
        if (ctors != null) {
            return new ConstructorResolver(this).autowireConstructor(beanName, mbd, ctors);
        }

        //3. 无参构造器
        Object beanInstance = getInstantiationStrategy().instantiate(mbd, beanName);
        BeanWrapper bw = new BeanWrapperImpl(beanInstance);
        bw.setConversionService(getConversionService());
        return bw;
    }


    //填充对象
    protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
        //1. 自动装配，处理@Autowired、@Value、@Inject等注解
        if(!mbd.isSynthetic()){
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof InstantiationAwareBeanPostProcessor) {
                    InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                    ibp.postProcessPropertyValues(bw.getWrappedInstance(), beanName);
                }
            }
        }

        //2. 属性访问，通过BeanWrapper为字段赋值
        PropertyValues pvs = mbd.getPropertyValues();
        if (pvs != null) {
            bw.setPropertyValues(pvs);
        }
    }


    //初始化
    protected Object initializeBean(String beanName, final Object bean, RootBeanDefinition mbd) {
        //1. 调用Aware接口
        invokeAwareMethods(bean);

        //2. 调用PostProcessor在Bean初始化之前进行处理（比如InitDestroyAnnotationBeanPostProcessor处理使用@PostConstruct的初始化方法）
        Object wrappedBean = bean;
        if (!mbd.isSynthetic()) {
            wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
        }

        //3. 调用初始化方法
        try {
            invokeInitMethods(wrappedBean, mbd);
        } catch (Exception e) {
            throw new RuntimeException("初始化Bean --> 调用init方法失败, beanName: " + beanName, e);
        }

        //4. 调用PostProcessor在Bean初始化之后进行处理（比如AbstractAutoProxyCreator创建代理对象）
        if (!mbd.isSynthetic()) {
            wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }
        return wrappedBean;
    }


    //Aware接口回调
    private void invokeAwareMethods(Object bean) {
        if(bean instanceof Aware){
            //注入BeanFactory
            if(bean instanceof BeanFactoryAware){
                ((BeanFactoryAware) bean).setBeanFactory(this);
            }
        }
    }


    //在Bean初始化之前执行后置处理器
    private Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) {
        Object result = existingBean;
        for (BeanPostProcessor processor : getBeanPostProcessors()) {
            Object current = processor.postProcessBeforeInitialization(result, beanName);
            if(current == null){
                return result;
            }
            result = current;
        }
        return result;
    }


    //实例化前，判断BeanBean的构造器（主要是AutowiredAnnotationBeanPostProcessor）
    protected Constructor<?>[] determineConstructorsFromBeanPostProcessors(Class<?> beanClass, String beanName) throws BeansException {
        if (beanClass != null) {
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof InstantiationAwareBeanPostProcessor) {
                    InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                    Constructor<?>[] ctors = ibp.determineCandidateConstructors(beanClass, beanName);
                    if (ctors != null) {
                        return ctors;
                    }
                }
            }
        }
        return null;
    }


    //初始化方法回调
    private void invokeInitMethods(final Object bean, RootBeanDefinition mbd) throws Exception {
        //如果是InitializingBean，调用初始化方法（主要是框架内部使用，检查各项属性是否设置成功，否则抛出异常，中止容器的创建过程）
        if(bean instanceof InitializingBean){
            ((InitializingBean) bean).afterPropertiesSet();
        }

        //调用自定义初始化方法，比如Xml或@Bean的initMethod属性指定的方法
        if(mbd != null){
            String initMethodName = mbd.getInitMethodName();
            if(initMethodName != null && !"afterPropertiesSet".equals(initMethodName)){
                Method initMethod = BeanUtils.findMethod(bean.getClass(), initMethodName);
                if(initMethod != null){
                    ReflectionUtils.makeAccessible(initMethod);
                    initMethod.invoke(bean);
                }
            }
        }
    }


    //在Bean初始化之后执行后置处理器
    private Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) {
        Object result = existingBean;
        for (BeanPostProcessor processor : getBeanPostProcessors()) {
            Object current = processor.postProcessAfterInitialization(result, beanName);
            if(current == null){
                return result;
            }
            result = current;
        }
        return result;
    }


    //注册需要执行销毁逻辑的Bean
    private void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
        /*
         * 判断当前对象是否需要销毁
         * 1) 实现了DisposableBean或AutoCloseable接口，或者BeanDefinition的destroyMethodName属性存在
         * 2) 或者存在声明了@PostConstruct注解的方法
         */
        if(bean != null && DisposableBeanAdapter.hasDestroyMethod(bean, mbd) ||
                DisposableBeanAdapter.hasApplicableProcessors(bean, getBeanPostProcessors())){
            DisposableBeanAdapter disposableBean = new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors());
            //将适配器对象注册到容器中
            registerDisposableBean(beanName, disposableBean);
        }
    }


    //重写父类AbstractBeanFactory的方法，在不实例化对象的前提下推断Bean的类型
    @Override
    protected Class<?> predictBeanType(String beanName, RootBeanDefinition mbd, Class<?>... typesToMatch) {
        return determineTargetType(beanName, mbd, typesToMatch);
    }


    protected Class<?> determineTargetType(String beanName, RootBeanDefinition mbd, Class<?>... typesToMatch) {
        Class<?> targetType = mbd.getTargetType();
        if (targetType == null) {
            //通过工厂方法创建的Bean
            if (mbd.getFactoryMethodName() != null) {
                targetType = getTypeForFactoryMethod(beanName, mbd);
            } else {
                targetType = resolveBeanClass(mbd, beanName, typesToMatch);
            }
            if (ObjectUtils.isEmpty(typesToMatch)) {
                mbd.resolvedTargetType = targetType;
            }
        }
        return targetType;
    }


    //获取工厂方法所创建的对象类型，即工厂方法的返回值类型。（这里仅考虑实例工厂方法，不处理静态工厂方法）
    protected Class<?> getTypeForFactoryMethod(String beanName, RootBeanDefinition mbd) {
        //如果已经解析过了，直接返回
        ResolvableType cachedReturnType = mbd.factoryMethodReturnType;
        if (cachedReturnType != null) {
            return cachedReturnType.resolve();
        }

        Class<?> factoryClass = null;       //工厂方法所在的类
        String factoryBeanName = mbd.getFactoryBeanName();
        if (factoryBeanName != null) {
            if (factoryBeanName.equals(beanName)) {
                throw new BeansException("通过工厂方法创建的Bean的名称不能与工厂方法所在Bean的名称相同");
            }

            factoryClass = getType(factoryBeanName);
        }
        if(factoryClass == null){
            return null;
        }
        factoryClass = ClassUtils.getUserClass(factoryClass);

        Class<?> commonType = null;         //多个工厂方法的通用返回类型，优先返回父类/接口的类型
        Method uniqueCandidate = null;
        Method[] candidates = ReflectionUtils.getUniqueDeclaredMethods(factoryClass);
        for (Method candidate : candidates) {

            if(mbd.isFactoryMethod(candidate)){
                //1) 第一次进入，commonType为null，赋值就是candidate的返回值
                //2) 第二次进入，说明有同名的方法。commonType不是null，uniqueCandidate为null。
                uniqueCandidate = (commonType == null ? candidate : null);
                commonType = ClassUtils.determineCommonAncestor(candidate.getReturnType(), commonType);

                // 如果有多个同名的工厂方法，那么要确保所有工厂方法的返回类型是一样的，或者有继承关系
                // 否则commonType为null，说明无法判断工厂方法所要创建的对象类型
                if(commonType == null){
                    return null;
                }
            }
        }

        if (commonType == null) {
            return null;
        }

        // 如果工厂方法是唯一的，则以该方法的返回值为准
        if (uniqueCandidate != null) {
            cachedReturnType = ResolvableType.forMethodReturnType(uniqueCandidate);
        }
        // 多个工厂方法则取其通用返回类型，可能是父类/接口
        else {
            cachedReturnType = ResolvableType.forClass(commonType);
        }

        mbd.factoryMethodReturnType = cachedReturnType;
        return cachedReturnType.resolve();
    }


    public InstantiationStrategy getInstantiationStrategy() {
        return instantiationStrategy;
    }
}
